#pragma once  

#include<iostream>
#include<cstdlib>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<string>
#include"Log.hpp"
#include<memory.h>
#include <arpa/inet.h>
#include <netinet/in.h>

using namespace std;
const int defaultfd= -1;
const std::string defaultip="0.0.0.0";
const int blocklog=10;
Log lg;
//枚举退出码
enum
{
    SockErro=1,
    BindError,
    ListenErro
};

class TcpServer;
class ThreadData
{
public:
    ThreadData(int fd,const string& ip,const uint16_t& port,TcpServer*t)
    :clientfd_(fd),clientip_(ip),clientport_(port),tsv(t)
    {}
public:
    int clientfd_;
    string clientip_;
    uint16_t clientport_;
    TcpServer* tsv;
};
class TcpServer
{
public:
    TcpServer(const uint16_t& port, const std::string& ip=defaultip):sockfd_(defaultfd),port_(port),ip_(defaultip)
    {
        
    }
    void InitServer()
    {
        sockfd_ =socket(AF_INET,SOCK_STREAM,0);
        if(sockfd_ <0)
        {
            lg(Info,"create socket,errno:%d,errstring:%s",errno,strerror(errno));
            exit(SockErro);
        }
        lg(Info,"create socket success,socket:%d",sockfd_);

        int opt=1;
        setsockopt(listensock_,SOL_SOCKET,SO_REUSEADDR|SO_REUSEPORT,&opt,sizeof(opt));
        
        struct sockaddr_in local;
        memset(&local,0,sizeof(local));
        //绑定地址信息
        local.sin_family=AF_INET;
        local.sin_addr.s_addr=inet_addr("192.168.229.129");
        local.sin_port=htons(port_);
        inet_aton(ip_.c_str(), &(local.sin_addr));
        //local.sin_addr.s_addr=0;

        if(bind(sockfd_,(struct sockaddr*)&local,sizeof(local))<0)
        {
            lg(Fatal,"bind error,errno:%d,srrstring:%s",errno,strerror(errno));
            exit(BindError);
        }
        //tcp是面向连接的
        if(listen(sockfd_,blocklog)<0)
        {
            lg(Fatal,"listen error:%d,errstring:%s",errno,strerror(errno));
            exit(ListenErro);
        }
        lg(Info,"Listen socket success,listensockfd:%d",sockfd_);

        
    }
    static void* Routine(void* args)
    {

        ThreadData* td=static_cast<ThreadData*>(args);
        td->tsv->Service(td->clientfd_,td->clientip_,td->clientport_);
        delete td;
        return nullptr;
    }
    void start()
    {
        for(; ;)
        {
            //获取新链接
            struct sockaddr_in client;
            socklen_t len=sizeof(client);
            int sockfd=accept(sockfd_,(struct sockaddr*)&client,&len);
            if(sockfd<0)
            {
                lg(Fatal,"sock creste erro:%d,errstring:%s",errno,strerror(errno));
            }
            lg(Info,"sockfd success,sockfd:%d",sockfd);
            //网络转主机序列
            uint16_t clientport=ntohl(client.sin_port);
            
            char clientip[32];
            inet_ntop(AF_INET,&(client.sin_addr),clientip,sizeof(clientip));
            //根据新连接进行通信
            lg(Info,"get a new link..., sockfd:%d,client ip:%s,client port:%d",sockfd,clientip,clientport);

            //
            //Service(sockfd,clientip,clientport);

            //多jin程版
            // pid_t id=fork();
            // if(id==0)
            // {
            //     close(listensock_);
            //     //
            //     Service(listensock_,clientip,clientport);
            //     close(sockfd_);
            // }
            //多线程版
            ThreadData* td=new ThreadData(sockfd,clientip,clientport,this);

            pthread_t tid;
            pthread_create(&tid,nullptr,Routine,td);


        }
    }
    void Service(int sockfd,const std::string& clienip,const uint16_t& clienport)
    {
        //提供一个服务 发消息 回消息

        char buffer[1024];
        while(true)
        {
            ssize_t n=read(sockfd,buffer,sizeof(buffer));
            if(n>0)
            {
                buffer[n]=0;
                std::cout<<"clien say# "<<buffer<<std::endl;
                std::string echo_string="tcpserver echo# ";
                echo_string+=buffer;
                write(sockfd,echo_string.c_str(),echo_string.size());
            }
        }
    }

    ~TcpServer()
    {}

private:
    int listensock_;
    int sockfd_;
    uint16_t port_;
    std::string ip_;
};